<?php

declare(strict_types=1);
/**
 * 微信API服务类
 * 处理微信相关的API调用，包括获取access_token、发送模板消息、获取用户信息等
 */

namespace app\common\service\third_party_api;

use think\facade\Cache;
use think\facade\Log;
use app\common\service\Util;
use Exception;

/**
 * 微信API服务类
 * 处理微信相关的API调用，包括获取access_token、发送模板消息、获取用户信息等
 */
class WechatApiService
{
    /**
     * 获取微信access_token
     * @return string|false access_token值或false(获取失败)
     */
    public function getAccessToken()
    {
        // 尝试从缓存获取
        $accessToken = Cache::get('wechat_access_token');
        if (!empty($accessToken)) {
            return $accessToken;
        }

        // 缓存不存在时，从微信服务器获取
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . config('wechat.app_id') . '&secret=' . config('wechat.app_secret');
        try {
            $rs = Util::sendPostRequest($url, [], [], 10);
            if (isset($rs['errcode'])) {
                Log::error('获取微信access_token失败: ' . $rs['errmsg']);
                return false;
            }
            // 缓存access_token，有效期减200秒以确保安全
            Cache::set('wechat_access_token', $rs['access_token'], $rs['expires_in'] - 200);
            return $rs['access_token'];
        } catch (Exception $e) {
            Log::error('获取微信access_token异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 发送模板消息
     * @param string $openid 用户openid
     * @param string $templateId 模板ID
     * @param array $data 模板数据
     * @param string $url 跳转URL
     * @return bool|array 发送结果
     */
    public function sendTemplateMessage($openid, $templateId, $data, $url = '')
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return false;
        }

        $sendData = [
            'touser' => $openid,
            'template_id' => $templateId,
            'page' => $url,
            'form_id' => '',
            'data' => $data
        ];

        $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=' . $accessToken;
        try {
            $rs = Util::sendPostRequest($url, $sendData, [], 10);
            if (isset($rs['errcode']) && $rs['errcode'] != 0) {
                Log::error('发送模板消息失败: ' . $rs['errmsg']);
                return false;
            }
            return $rs;
        } catch (Exception $e) {
            Log::error('发送模板消息异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 获取用户信息
     * @param string $openid 用户openid
     * @return array|false 用户信息数组或false(获取失败)
     */
    public function getUserInfo($openid)
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return false;
        }

        $url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=' . $accessToken . '&openid=' . $openid . '&lang=zh_CN';
        try {
            $rs = Util::sendPostRequest($url, [], [], 10);
            if (isset($rs['errcode'])) {
                Log::error('获取用户信息失败: ' . $rs['errmsg']);
                return false;
            }
            return $rs;
        } catch (Exception $e) {
            Log::error('获取用户信息异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 生成JS-SDK签名
     * @param string $url 当前页面URL
     * @return array|false 签名信息或false(生成失败)
     */
    public function generateJsSdkSign($url)
    {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return false;
        }

        // 尝试从缓存获取jsapi_ticket
        $jsapiTicket = Cache::get('wechat_jsapi_ticket');
        if (empty($jsapiTicket)) {
            $urlTicket = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $accessToken . '&type=jsapi';
            try {
                $rs = Util::sendPostRequest($urlTicket, [], [], 10);
                if (isset($rs['errcode']) && $rs['errcode'] != 0) {
                    Log::error('获取jsapi_ticket失败: ' . $rs['errmsg']);
                    return false;
                }
                // 缓存jsapi_ticket
                Cache::set('wechat_jsapi_ticket', $rs['ticket'], $rs['expires_in'] - 200);
                $jsapiTicket = $rs['ticket'];
            } catch (Exception $e) {
                Log::error('获取jsapi_ticket异常: ' . $e->getMessage());
                return false;
            }
        }

        // 生成签名
        $noncestr = uniqid();
        $timestamp = time();
        $string1 = 'jsapi_ticket=' . $jsapiTicket . '&noncestr=' . $noncestr . '&timestamp=' . $timestamp . '&url=' . $url;
        $signature = sha1($string1);

        return [
            'appId' => config('wechat.app_id'),
            'timestamp' => $timestamp,
            'nonceStr' => $noncestr,
            'signature' => $signature
        ];
    }

    /**
     * 通过code获取微信openid和access_token
     * @param string $code 微信授权code
     * @return array|false 微信用户信息或false(获取失败)
     */
    public function getOpenIdByCode($code)
    {
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . config('wechat.app_id') . '&secret=' . config('wechat.app_secret') . '&code='.$code.'&grant_type=authorization_code';
        try {
            $rs = Util::sendPostRequest($url, [], [], 10);
            if (isset($rs['errcode'])) {
                Log::error('获取微信openid失败: ' . $rs['errmsg']);
                return false;
            }
            return $rs;
        } catch (Exception $e) {
            Log::error('获取微信openid异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 通过snsAccessToken获取微信用户详细信息
     * @param string $snsAccessToken 微信授权snsAccessToken
     * @param string $openid 用户openid
     * @return array|false 微信用户详细信息或false(获取失败)
     */
    public function getUserInfoBySnsAccessToken($snsAccessToken, $openid)
    {
        $url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $snsAccessToken . '&openid=' . $openid . '&lang=zh_CN';
        try {
            $rs = Util::sendPostRequest($url, [], [], 10);
            if (isset($rs['errcode'])) {
                Log::error('获取微信用户详细信息失败: ' . $rs['errmsg']);
                return false;
            }
            return $rs;
        } catch (Exception $e) {
            Log::error('获取微信用户详细信息异常: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 获取OAuth授权信息
     * @param string $url OAuth请求URL
     * @return array|false 授权信息或false(获取失败)
     */
    public function getOAuthInfo($url)
    {
        try {
            $rs = Util::sendPostRequest($url, [], [], 10);
            if (isset($rs['errcode'])) {
                Log::error('获取OAuth授权信息失败: ' . $rs['errmsg']);
                return false;
            }
            return $rs;
        } catch (Exception $e) {
            Log::error('获取OAuth授权信息异常: ' . $e->getMessage());
            return false;
        }
    }
}
